package se.sll.itintegration.catalogue.gui.service.view.capacity;

import java.util.ArrayList;
import java.util.List;

import se.sll.service.catalogue.common.Translator;
import se.sll.service.catalogue.common.rest.model.CodeSystemCode;

public class CodeSystemCodeCapacityTranslator implements Translator<List<CodeSystemCode>, CapacityViewProduct> {
    private static final CodeSystemCodeCapacityTranslator INSTANCE = new CodeSystemCodeCapacityTranslator();

    private CodeSystemCodeCapacityTranslator() {
    }

    @Override
    public CapacityViewProduct translate(List<CodeSystemCode> from) {
        return translateTo(from, new CapacityViewProduct());
    }

    /**
     * Adds capacity information from the product subsystem to the given CapacityViewProduct.
     * This is information about which capacity codes CAN be coded on the given product.
     * Instance-specific information such as value and validTo is added later by
     * CapacityTranslator.
     * 
     * The transformation from abstract {code, value} form to the more structured presentation
     * form makes this translator quite complex. Waiting time codes are paired into
     * CapacityViewCapacity objects, and other codes are translated into their own fields in
     * CapacityViewProduct.
     */
    @Override
    public CapacityViewProduct translateTo(List<CodeSystemCode> from, CapacityViewProduct to) {
        List<CapacityViewCapacity> caps = to.getCapacities();
        if (caps == null) {
            caps = new ArrayList<>();
            to.setCapacities(caps);
        }
        if (from != null) {
            for (CodeSystemCode c : from) {
                if (CapacityConstants.CODESYSTEM_CAPACITY.equals(c.getOid())) {
                    String code = c.getCode();
                    switch (code) {
                    case CapacityConstants.CODE_AVAILABLE_CAPACITY:
                        to.setAvailableCrossRegionCapacityActive(true);
                        break;

                    case CapacityConstants.CODE_REFERRAL_INFORMATION:
                        to.setReferralInfoActive(true);
                        break;
                    }
                }
            }

            addCapacity(caps, from, CapacityConstants.LONG_DISPLAY_NAME_APPOINTMENT, CapacityConstants.SHORT_DISPLAY_NAME_APPOINTMENT,
                    CapacityConstants.CODE_WAIT_TIME_APPOINTMENT, CapacityConstants.CODE_WAIT_TIME_APPOINTMENT_PRIORITY);
            addCapacity(caps, from, CapacityConstants.LONG_DISPLAY_NAME_EXAMINATION, CapacityConstants.SHORT_DISPLAY_NAME_EXAMINATION,
                    CapacityConstants.CODE_WAIT_TIME_EXAMINATION, CapacityConstants.CODE_WAIT_TIME_EXAMINATION_PRIORITY);
            addCapacity(caps, from, CapacityConstants.LONG_DISPLAY_NAME_TREATMENT, CapacityConstants.SHORT_DISPLAY_NAME_TREATMENT,
                    CapacityConstants.CODE_WAIT_TIME_TREATMENT, CapacityConstants.CODE_WAIT_TIME_TREATMENT_PRIORITY);

        }
        return to;
    }

    private static void addCapacity(List<CapacityViewCapacity> caps, List<CodeSystemCode> from,
            String longDisplayName, String shortDisplayName, String waitTimeCode, String waitTimePriorityCode) {
        boolean hasWaitTime = false;
        boolean hasWaitTimePriority = false;

        for (CodeSystemCode c : from) {
            if (CapacityConstants.CODESYSTEM_CAPACITY.equals(c.getOid())) {
                String code = c.getCode();
                if (waitTimeCode.equals(code)) {
                    hasWaitTime = true;
                } else if (waitTimePriorityCode.equals(code)) {
                    hasWaitTimePriority = true;
                }
            }
        }

        if (hasWaitTime || hasWaitTimePriority) {
            CapacityViewCapacity viewCapacity = new CapacityViewCapacity();
            viewCapacity.setLongDisplayName(longDisplayName);
            viewCapacity.setShortDisplayName(shortDisplayName);
            viewCapacity.setCodeSystem(CapacityConstants.CODESYSTEM_CAPACITY);
            viewCapacity.setWaitTimeActive(hasWaitTime);
            viewCapacity.setWaitTimeCode(waitTimeCode);
            viewCapacity.setWaitTimePriorityActive(hasWaitTimePriority);
            viewCapacity.setWaitTimePriorityCode(waitTimePriorityCode);
            caps.add(viewCapacity);
        }
    }

    public static CodeSystemCodeCapacityTranslator getInstance() {
        return INSTANCE;
    }
}
